﻿/*
 * Nix PBEM Game Engine.
 * Copyright (C) 2008, Lauris Bukšis-Haberkorns
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

using System;
using System.Collections.Generic;
using System.Text;

using Nix.PBeM.Engine.DataTypes.Orders;
using Nix.PBeM.Engine.DataTypes;
using Nix.PBeM.Engine.DataSources;

namespace Nix.PBeM.Engine.Process.Orders
{
	public class StackOrder : OrderBase
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="StackOrder"/> class.
		/// </summary>
		public StackOrder ()
			: base("STACK")
		{
			this.Syntax = string.Format("{0} unit-id", this.Keyword);
			this.Description = "This order executes when a unit is at the same location as the designed unit. The unit UNSTACKs, if necessary, and stacks under the leadership of the designated unit.  If the unit under which you are attempting to stack doesn't consider you at least ally, this order will fail unless the leader issued the ACCEPT order. You are always visible to the unit under which you are stacking.";
			this.Type = OrderType.Stack;
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="StackOrder"/> class.
		/// </summary>
		/// <param name="entity">The entity.</param>
		/// <param name="parser">The parser.</param>
		public StackOrder ( OrderEntity entity, StringLineParser parser )
			: this ()
		{
			this.Entity = entity;
			this.Parser = parser;
		}

		/// <summary>
		/// Create order instance.
		/// </summary>
		/// <param name="entity">The entity.</param>
		/// <returns>Order instance.</returns>
		public override OrderBase Create ( OrderEntity entity, StringLineParser parser )
		{
			return new StackOrder(entity, parser);
		}

		private Unit leader = null;

		public override void Parse ()
		{
			if ( this.Entity.GetType() != typeof(Unit) )
				throw new OrderParseException("This order can be specified only for unit.");

			string utag = this.Parser.GetOptionalWord();
			if ( string.IsNullOrEmpty(utag) )
				throw new OrderParseException("Unit id not sepcified.");
			this.leader = Engine.Instance.FindUnit(utag);
			if (this.leader == null)
				throw new OrderParseException("Invalid unit id specified.");
		}

		/// <summary>
		/// Order duration.
		/// </summary>
		/// <value></value>
		public override int Duration
		{
			get
			{
				return base.Duration;
			}
			set
			{
				// Allow setting only duration 1 or 0 when executed
				if ( value > 1 || value < 0 )
					base.Duration = 1;
				else
					base.Duration = value;
			}
		}

		public override void Execute ()
		{
			base.Execute();

			Interraction inter = ((Unit)this.Entity).MayInterract(this.leader);
			if (inter == Interraction.None ||
					(inter == Interraction.SameLocation && this.leader.FindAcceptOrder((Unit)this.Entity) == null) )
			{
				this.Entity.AddEventMessage(string.Format("Can not stack as there is no such unit in this location."));
				this.ExecutionFailed = true;
				return;
			}

			// Unstack
			UnstackOrder.Unstack((Unit)this.Entity);
			// Stack under new leader
			StackOrder.StackUnder(this.leader, (Unit)this.Entity);
			this.CompleteExecution();
		}
		
		public static void StackUnder(Unit leader, Unit follower)
		{
			AcceptOrder accept = leader.FindAcceptOrder(follower);

			// Stack under unit if it's allowing it
			if ( leader.Faction.AtLeastStance(follower, Engine.Instance.StanceManager.MinimalStackStance) ||
					accept != null )
			{
				if (accept != null)
					accept.DoExecute();
				follower.Leader = leader;
				leader.AddEventMessage(string.Format("{0} stacked under your leadership.", follower));
				follower.AddEventMessage(string.Format("Stacks under {0} leadership.", leader));
			}
			else
			{
				// Stacking was refused
				leader.AddEventMessage(string.Format("{0} tried to stack under your leadership but was refused.", follower));
				follower.AddEventMessage(string.Format("{0} does not allow stacking under his leadership.", leader));
			}
		}
	}
}
